<?php

namespace services\buss;

use api\modules\v1\forms\buss\TargetContentForm;
use common\components\Service;
use common\helpers\CommonHelper;
use common\helpers\DateHelper;
use common\helpers\RedisHelper;
use common\models\base\CommonStatus;
use common\models\buss\Platform;
use common\models\buss\TargetContent;
use common\models\member\Member;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use services\base\CommonStatusService;
use services\log\LogMemberOpService;
use services\member\MemberService;
use Yii;

/**
 * Class TargetContentService
 * @package services\buss
 */
class TargetContentService extends Service
{
    /**
     * 选题列表
     * @param array $params
     * @param int $page
     * @param int $pageSize
     * @return array
     */
    public function getListPage(array $params = [], int $page = 0, int $pageSize = 0): array
    {
        $query = TargetContent::find()->alias('tc')
            ->select([
                'tc.*',
                'm.realname created_member_name',
            ])
            ->innerJoin(Member::tableName().' m', 'tc.created_member_id = m.id')
            ->where([
                'tc.status' => [TargetContent::STATUS_ENABLE, TargetContent::STATUS_INVALID],
            ]);
        if (isset($params['created_stime']) && $params['created_stime']) {
            $query->andWhere(['>=', 'tc.created_at', strtotime($params['created_stime'])]);
        }
        if (isset($params['created_etime']) && $params['created_etime']) {
            $query->andWhere(['<=', 'tc.created_at', strtotime($params['created_etime'].' 23:59:59')]);
        }
        if (isset($params['keywords']) && $params['keywords']) {
            $query->andWhere(['like', 'tc.title', $params['keywords']]);
        }
        if (isset($params['platform_name']) && $params['platform_name']) {
            $query->andWhere(['tc.platform_name' => $params['platform_name']]);
        }
        if (isset($params['t_id']) && $params['t_id']) {
            $query->andWhere(['tc.t_id' => $params['t_id']]);
        }
        if (isset($params['c_id']) && $params['c_id']) {
            $query->andWhere(['tc.c_id' => $params['c_id']]);
        }
        if (isset($params['created_member_id']) && $params['created_member_id']) {
            $query->andWhere(['tc.created_member_id' => $params['created_member_id']]);
        }
        // 排序
        $order = [];
        if (isset($params['order_column']) && $params['order_column']) {
            $sort = isset($params['order_sort']) && $params['order_sort'] == 'asc' ? SORT_ASC : SORT_DESC;
            switch ($params['order_column']) {
                case 'like_num':
                case 'comment_num':
                case 'collect_num':
                case 'forward_num':
                    $order["{$params['order_column']}"] = $sort;
                    break;
                default :
                    break;
            }
            $order && $order['tc.id'] = SORT_DESC;
        }
        empty($order) && $order = ['tc.status' => SORT_DESC, 'tc.id' => SORT_DESC];
        return $this->getListPageRes($query, $page, $pageSize, $order);
    }

    /**
     * 格式化列表
     * @param array $data
     * @return array
     */
    public function getListPageFormat(array $data = []): array
    {
        $list = [];
        foreach ($data as $row) {
            $list[] = [
                'id' => $row['id'],
                'title' => $row['title'],
                'url' => CommonHelper::getUrlFormat($row['url']),
                'account_name' => $row['account_name'],
                't_name' => RedisHelper::getCommonStatus($row['t_id'])->name ?? '',
                'platform_name' => $row['platform_name'],
                'like_num' => CommonHelper::getNumFormat($row['like_num']),
                'comment_num' => CommonHelper::getNumFormat($row['comment_num']),
                'collect_num' => CommonHelper::getNumFormat($row['collect_num']),
                'forward_num' => CommonHelper::getNumFormat($row['forward_num']),
                'c_name' => RedisHelper::getCommonStatus($row['c_id'])->name ?? '',
                'topic' => $row['topic'],
                'created_member_name' => $row['created_member_name'],
                'created_at_str' => DateHelper::timestampToDate($row['created_at'], DateHelper::DATE_FORMAT_1),
                'change_date' => DateHelper::timestampToDate(strtotime($row['change_date']), DateHelper::DATE_FORMAT_1),
            ];
        }
        return $list;
    }

    /**
     * 获取选题创建人IDs
     * @return array
     */
    public static function getCreateMemberIds(): array
    {
        return TargetContent::find()
            ->select(['created_member_id'])
            ->andWhere(['status' => [TargetContent::STATUS_ENABLE, TargetContent::STATUS_INVALID]])
            ->column();
    }

    /**
     * 获取选题平台列表
     * @return array
     */
    public static function getPlatformList(): array
    {
        $platforms = TargetContent::find()
            ->select(['platform_name'])
            ->andWhere(['status' => [TargetContent::STATUS_ENABLE, TargetContent::STATUS_INVALID]])
            ->andWhere(['!=', 'platform_name', ''])
            ->groupBy('platform_name')
            ->column();
        $data = [];
        foreach ($platforms as $row) {
            $data[] = [
                'value' => $row,
                'label' => $row,
            ];
        }
        return $data;
    }

    /**
     * 操作人列表
     * @return array
     */
    public static function getCreatedMemberList(): array
    {
        $ids = self::getCreateMemberIds();
        return $ids ? MemberService::getListCondition($ids) : [];
    }

    /**
     * 列表筛选项
     * @return array
     */
    public function getSelectCondition(): array
    {
        return [
            'created_member' => self::getCreatedMemberList(),
            'classify' => CommonStatusService::getListCondition(CommonStatus::TYPE_CONTENT),
            'type' => CommonStatusService::getListCondition(CommonStatus::TYPE_ACCOUNTS),
            'platform' => self::getPlatformList()
        ];
    }

    /**
     * 选题详情
     * @param array $params
     * @return array
     */
    public function getInfo(int $id): array
    {
        $data = [];
        // 选题信息
        $targetContent = TargetContent::findOne($id);
        if ($targetContent) {
            $data = [
                'id' => $targetContent->id,
                'title' => $targetContent->title,
                'url' => $targetContent->url,
                'account_name' => $targetContent->account_name,
                't_id' => $targetContent->t_id,
                'platform_name' => $targetContent->platform_name,
                'c_id' => $targetContent->c_id,
                'like_num' => CommonHelper::getNumFormat($targetContent->like_num),
                'comment_num' => CommonHelper::getNumFormat($targetContent->comment_num),
                'collect_num' => CommonHelper::getNumFormat($targetContent->collect_num),
                'forward_num' => CommonHelper::getNumFormat($targetContent->forward_num),
                'topic' => $targetContent->topic,
            ];
        }
        $condition = [
            'platform' => self::getPlatformList(),
            'type' => CommonStatusService::getEditCondition(CommonStatus::TYPE_ACCOUNTS, $data['t_id'] ?? null),
            'classify' => CommonStatusService::getEditCondition(CommonStatus::TYPE_CONTENT, $data['c_id'] ?? null),
        ];
        if ($targetContent) {
            if (in_array($data['t_id'], array_column($condition['type'], 'value')) === false) {
                $data['t_id'] = 0;
            }
            if (in_array($data['c_id'], array_column($condition['classify'], 'value')) === false) {
                $data['c_id'] = 0;
            }
        }
        return array_merge($data, ['condition' => $condition]);
    }

    /**
     * 编辑选题
     * @param TargetContent $content
     * @param TargetContentForm $model
     * @return TargetContent
     * @throws \Exception
     */
    public static function editModel(TargetContent $content, TargetContentForm $model): TargetContent
    {
        $content->title = $model->title ?: '';
        $content->url = $model->url ?: '';
        $content->account_name = $model->account_name;
        $content->t_id = $model->t_id;
        $content->platform_name = $model->platform_name;
        $content->like_num = is_numeric($model->like_num) ? $model->like_num : null;
        $content->collect_num = is_numeric($model->collect_num) ? $model->collect_num : null;
        $content->comment_num = is_numeric($model->comment_num) ? $model->comment_num : null;
        $content->forward_num = is_numeric($model->forward_num) ? $model->forward_num : null;
        $content->c_id = $model->c_id;
        $content->topic = $model->topic ?: '';
        if ($model->getScenario() == 'create') {
            $content->created_member_id = Yii::$app->user->identity->member_id;
            $content->change_date = DateHelper::timestampToDate(time());
            $content->operation_id = Yii::$app->user->identity->member_id;
            $content->operation_name = Yii::$app->user->identity->member->realname;
            $content->status = TargetContent::STATUS_ENABLE;
        }
        $content->saveAndCheckResult();

        return $content;
    }

    /**
     * 新增选题
     * @param TargetContentForm $model
     * @return array
     */
    public function create(TargetContentForm $model): array
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            // 1-1.新增选题
            $targetContent = new TargetContent();
            $targetContent = self::editModel($targetContent, $model);
            // 2.日志
            LogMemberOpService::createTargetContentLog($model, $targetContent);

            $transaction->commit();
            return ['id' => $targetContent->id];
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }
    }

    /**
     * 编辑选题
     * @param TargetContentForm $model
     * @return array
     */
    public function edit(TargetContentForm $model): array
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            // 1-1.更新选题
            $oldTargetContent = new TargetContent();
            $oldTargetContent->setAttributes($model->getTargetContent()->getAttributes());
            $targetContent = self::editModel($model->getTargetContent(), $model);
            // 2.日志
            if (LogMemberOpService::createTargetContentLog($model, $targetContent, $oldTargetContent)) {// 存在日志说明表单有更新
                // 3.更新修改日期
                $targetContent->change_date = DateHelper::timestampToDate(time());
                $targetContent->operation_id = Yii::$app->user->identity->member_id;
                $targetContent->operation_name = Yii::$app->user->identity->member->realname;
                $targetContent->saveAndCheckResult();
            }

            $transaction->commit();
            return ['id' => $targetContent->id];
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }
    }

    /**
     * 删除选题
     * @param TargetContentForm $model
     * @return array
     */
    public function delete(TargetContentForm $model): array
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            // 1.更新选题
            $targetContent = $model->getTargetContent();
            $targetContent->status = TargetContent::STATUS_DELETE;
            $targetContent->operation_id = Yii::$app->user->identity->member_id;
            $targetContent->operation_name = Yii::$app->user->identity->member->realname;
            $targetContent->saveAndCheckResult();
            // 2.日志
            LogMemberOpService::createTargetContentLog($model, $targetContent);

            $transaction->commit();
            return ['id' => $targetContent->id];
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }
    }

    /**
     * 生成模板文件
     * @return void
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     */
    public function createTmpExecl()
    {
        $newExecl = new Spreadsheet();
        $objSheet = $newExecl->getActiveSheet();
        $objSheet->setTitle('Sheet1');
        $title = [
            '标题', '链接网址', '归属账号', '账号类型', '平台', '点赞', '收藏', '评论', '转发', '分类', '话题'
        ];
        $styleArray = [
            'alignment' => [
                'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
            ],
        ];
        foreach ($title as $key => $val) {
            $col = Coordinate::stringFromColumnIndex($key+1);
            $objSheet->setCellValue("{$col}1", $val);
            $objSheet->getStyle("{$col}1")->applyFromArray($styleArray);
            $objSheet->getColumnDimension($col)->setWidth(15);
//            $objSheet->getColumnDimension($col)->setAutoSize(true);
        }
        $font = [
            'font' => [
                'blod' => true,
                'size' => 13,
            ]
        ];
        $startCol = Coordinate::stringFromColumnIndex(1);
        $endCol = Coordinate::stringFromColumnIndex(count($title));
        $objSheet->getStyle("{$startCol}1:{$endCol}1")->applyFromArray($font);

        // 账号类型
        $index = 'D';
        $types = CommonStatusService::getEditCondition(CommonStatus::TYPE_ACCOUNTS);
        $typeStr = implode(',', array_column($types, 'label'));
        $objValidation = $objSheet->getCell("{$index}2")->getDataValidation();
        $objValidation->setType(DataValidation::TYPE_LIST)
            ->setErrorStyle(DataValidation::STYLE_STOP)
            ->setAllowBlank(true)// 是否允许为空
            ->setShowInputMessage(true)
            ->setShowErrorMessage(true)
            ->setShowDropDown(true)
            ->setErrorTitle('账号类型错误')
            ->setError('请选择账号类型')
//            ->setPromptTitle('提示标题')
            ->setFormula1('"'.$typeStr.'"')
            ->setSqref("{$index}2:{$index}1048576");
        // 分类
        $index = 'J';
        $types = CommonStatusService::getEditCondition(CommonStatus::TYPE_CONTENT);
        $typeStr = implode(',', array_column($types, 'label'));
        $objValidation = $objSheet->getCell("{$index}2")->getDataValidation();
        $objValidation->setType(DataValidation::TYPE_LIST)
            ->setErrorStyle(DataValidation::STYLE_STOP)
            ->setAllowBlank(true)// 是否允许为空
            ->setShowInputMessage(true)
            ->setShowErrorMessage(true)
            ->setShowDropDown(true)
            ->setErrorTitle('分类错误')
            ->setError('请选择分类')
//            ->setPromptTitle('提示标题')
            ->setFormula1('"'.$typeStr.'"')
            ->setSqref("{$index}2:{$index}1048576");

        // 下载
        $dir = Yii::getAlias('@attachment').'/tmp/execl/';
        !is_dir($dir) && mkdir($dir, 0777, true);
        $downloadFileName = '模板.xlsx';
        $objWriter = IOFactory::createWriter($newExecl, IOFactory::READER_XLSX);
        $objWriter->save($dir.$downloadFileName);

        // 输出文件
        Yii::$app->response->sendFile($dir.$downloadFileName, $downloadFileName);
        // 删除临时文件
        @unlink($dir.$downloadFileName);
    }

    /**
     * 解析execl数据
     * @return array
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     */
    public function parseExeclData(): array
    {
        $file = $_FILES['file'] ?? [];
        if (empty($file)) {
            throw new \Exception('文件不存在', 422);
        }
        if ($file['error'] != UPLOAD_ERR_OK) {
            throw new \Exception("文件上传失败【错误代码：{$file['error']}】", 422);
        }
        $typeArr = [
            'application/vnd.ms-excel',// xls
            'application/wps-office.xls',// xls
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',// xlsx
            'application/wps-office.xlsx',// xlsx
        ];
        if (in_array($file['type'], $typeArr) === false) {
            throw new \Exception("上传文件类型错误，type: {$file['type']}【支持xls、xlsx格式】", 422);
        }
        $fileArr = explode('.', $file['name']);
        // 解析Excel文件
        $reader = IOFactory::createReader($fileArr[1] == 'xls' ? IOFactory::READER_XLS : IOFactory::READER_XLSX);
        $reader->setReadDataOnly(true);
        $spreadsheet = $reader->load($file['tmp_name']);
        $worksheet = $spreadsheet->getActiveSheet();
        $highestRow = $worksheet->getHighestRow(); // 总行数
        if ($highestRow <= 0) {
            return [];
        }

        $data = [];
        $error = [];
        $commonStatusList = $platformList = [];
        for ($row = 2; $row <= $highestRow; $row++) {
//            $isError = false;
            $time = time();
            $title = $worksheet->getCell(Coordinate::stringFromColumnIndex(1) . $row)->getValue();
            $url = $worksheet->getCell(Coordinate::stringFromColumnIndex(2) . $row)->getValue();
            $accountName = $worksheet->getCell(Coordinate::stringFromColumnIndex(3) . $row)->getValue();
            $tName = $worksheet->getCell(Coordinate::stringFromColumnIndex(4) . $row)->getValue();
            $platformName = $worksheet->getCell(Coordinate::stringFromColumnIndex(5) . $row)->getValue();
            $likeNum = $worksheet->getCell(Coordinate::stringFromColumnIndex(6) . $row)->getValue();
            $collectNum = $worksheet->getCell(Coordinate::stringFromColumnIndex(7) . $row)->getValue();
            $commentNum = $worksheet->getCell(Coordinate::stringFromColumnIndex(8) . $row)->getValue();
            $forwardNum = $worksheet->getCell(Coordinate::stringFromColumnIndex(9) . $row)->getValue();
            $cName = $worksheet->getCell(Coordinate::stringFromColumnIndex(10) . $row)->getValue();
            $topic = $worksheet->getCell(Coordinate::stringFromColumnIndex(11) . $row)->getValue();
            // 都不存在，则跳过
            if (!($title || $accountName || $url || $tName || $platformName || $likeNum || $collectNum || $commentNum || $forwardNum || $cName || $topic)) {
                continue;
            }
            // 验证必填
            if ((($url || $tName || $platformName || $likeNum || $collectNum || $commentNum || $forwardNum || $cName || $topic) && (empty($title) || empty($accountName)))
                || ($title && empty($accountName))
                || (empty($title) && $accountName)
            ) {
                $errorMsg = "第{$row}行";
                empty($title) && $errorMsg .= "【标题不能为空】";
                empty($accountName) && $errorMsg .= "【归属人不能为空】";
                $error[] = $errorMsg;
                continue;
            }

            // 类型
//            $errorMsg = "第{$row}行";
            $commonStatusList[$tName] = $commonStatusList[$tName] ?? CommonStatus::findOne([
                'name' => $tName,
                'type' => CommonStatus::TYPE_ACCOUNTS,
                'status' => CommonStatus::STATUS_ENABLE
            ]);
            /*if (empty($commonStatusList[$tName])) {
                $isError = true;
                $errorMsg .= "【'{$tName}'账号类型不存在】";
            }*/
            // 分类
            $commonStatusList[$cName] = $commonStatusList[$cName] ?? CommonStatus::findOne([
                'name' => $cName,
                'type' => CommonStatus::TYPE_CONTENT,
                'status' => CommonStatus::STATUS_ENABLE
            ]);
            /*if (empty($commonStatusList[$cName])) {
                $isError = true;
                $errorMsg .= "【'{$cName}'分类不存在】";
            }*/
//            if ($isError) {
//                $error[] = $errorMsg;
//                continue;
//            }

            $data[] = [
                $title,
                $url ?: '',
                $accountName,
                $commonStatusList[$tName]->id ?? 0,
                $platformName ?: '',
                $commonStatusList[$cName]->id ?? 0,
                is_numeric($likeNum) ? $likeNum : null,
                is_numeric($collectNum) ? $collectNum : null,
                is_numeric($commentNum) ? $commentNum : null,
                is_numeric($forwardNum) ? $forwardNum : null,
                $topic ?: '',
                Yii::$app->user->identity->member_id,
                Yii::$app->user->identity->member_id,
                Yii::$app->user->identity->member->realname,
                TargetContent::STATUS_ENABLE,
                DateHelper::timestampToDate($time),
                $time,
                $time,
            ];
        }
        // 删除临时文件
        unlink($file['tmp_name']);
        if ($error) {
            $errorMsg = implode(',', $error);
            throw new \Exception("{$errorMsg}", 422);
        }

        return [
            'data' => $data,
//            'repeat_ids' => $repeatIds,
        ];
    }

    /**
     * 导入选题模板
     * @return array
     */
    public function uploadExecl(): array
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();
            // 解析文件数据
            try {
                $data = $this->parseExeclData();
            } catch (\Exception $e1) {
                $transaction->rollBack();
                return CommonHelper::api(422, $e1->getMessage());
            }

            if ($data['data']) {
                // 1.批量新增
                Yii::$app->db->createCommand()->batchInsert(
                    TargetContent::tableName(),
                    ['title', 'url', 'account_name', 't_id', 'platform_name', 'c_id', 'like_num', 'comment_num', 'collect_num', 'forward_num', 'topic', 'created_member_id', 'operation_id', 'operation_name', 'status', 'change_date', 'created_at', 'updated_at'],
                    $data['data']
                )->execute();
                // 2.日志
                LogMemberOpService::createTargetContentUploadLog($data['data']);
            }
            $transaction->commit();

            return [];
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }
    }
}
